package com.aivin.maproutelib.manager;

import com.aivin.maproutelib.area.AreaMassif;
import com.aivin.maproutelib.bean.WaypointInfo;
import com.aivin.maproutelib.line.ScanLine;
import com.aivin.maproutelib.tool.MapTool;
import com.aivin.maproutelib.tool.WkLogTool;

import java.util.ArrayList;
import java.util.List;

/**
 * 管理航线规划具体计算等
 */
class CalculationManager {
    /**需要测绘的地块*/
    private AreaMassif mAreaMassif;

    CalculationManager(AreaMassif areaMassif) {
        mAreaMassif = areaMassif;
    }


    /**
     * 用户输入喷幅 ，返回优化后的喷幅
     * @param start 开始点
     * @param direction 方向
     * @param len 用户输入的喷幅
     * @param ratio 比例，用来换算地图上的喷幅的
     * @return  返回优化后的喷幅
     */
    private double getperfectLen(WaypointInfo start, float direction, double len, double ratio) {
        mAreaMassif.len = len;
        double deltaB = len * ratio;

        // 距离相隔最大的两条切割线的距离
        double maxDeltaB = mAreaMassif.getMaxDeltaB(start, direction);
        double maybeTime = maxDeltaB / deltaB;//理论扫描次数

        int realTime; // 最终的切割次数
        if ( maybeTime % 1 <= 0.01 && (int)maybeTime % 2 == 0 ) {
            realTime = (int) maybeTime;
        } else {
            if ((int)maybeTime % 2 == 0) {
                realTime = (int)maybeTime + 2;
            } else {
                realTime = (int)maybeTime + 1;
            }
        }

        return maxDeltaB / realTime;
    }


    /**
     * 获得比例 , 结果不是固定的 .
     */
    private double getDisRatio(ScanLine scanLine ) {
        double maxDis = 0;
        // 距离scanline距离最大的点
        WaypointInfo maxDisP = null;

        for (WaypointInfo point : mAreaMassif.boundaryLatLngList) {
            double dis = MapTool.getPointToLineDistance(point ,scanLine);
            if (dis > maxDis) {
                maxDis = dis;
                maxDisP = point;
            }
        }

        if(maxDisP==null){
            throw new RuntimeException("数据计算出错...") ;
        }

        // 过maxDisP 且与 scanLine 垂直的直线 与  scanLine的相交点
        WaypointInfo intersectionPoint;
        if (scanLine.k == 0) {
            intersectionPoint = new WaypointInfo(maxDisP.getLatitude(), scanLine.b);
        } else {
            ScanLine line = new ScanLine(maxDisP, -1 / scanLine.k);
            intersectionPoint = MapTool.getIntersectionPoint(line,scanLine);
        }
        // 求 maxDisP 到scanLine的 地球上的实际距离
        double distance = MapTool.getDistance( maxDisP.getLatLng(), intersectionPoint.getLatLng() );
        return maxDis / distance * Math.sqrt(1 + scanLine.k * scanLine.k);
    }


    /**
     * todo 计算生成的 所有 航线点
     * @param startPoint  起飞点
     * @return 计算出的所有航线点
     */
     List<WaypointInfo> getAllFlyPoints(WaypointInfo startPoint, float direction, double len ) {

        ScanLine starScanLine = new ScanLine(startPoint, direction);
        double ratio = getDisRatio(starScanLine );
        double detaB = getperfectLen(startPoint, direction, len, ratio);

        // 扫描方案1
        List<WaypointInfo> points1 = getPoints(startPoint ,starScanLine , detaB);
        // 扫描方案2
        List<WaypointInfo> points2 =  getPoints(startPoint ,starScanLine , -detaB);
        // 选择从方案1和方案2中选一个
        List<WaypointInfo> waypointInfos = points1.size() > points2.size() ? points1: points2   ;
        WkLogTool.showLog("size1= "+ points1.size()+"   size2="+points2.size()+"  last="+waypointInfos.size()) ;

         List<WaypointInfo> allPoints = new ArrayList<>();
         allPoints.addAll(points1);
         allPoints.addAll(points2);

        return waypointInfos;
//        return allPoints;
    }


    private List<WaypointInfo> getPoints(WaypointInfo start ,ScanLine line ,double detaB ){
        line.reset();//扫描线重置
        line.addDaltaB(detaB / 2);  // 为了不让药物喷洒浪费，就要把无人机移动半个喷幅

        List<WaypointInfo> points = new ArrayList<>();
        points.add(start); // 起飞点也要加入航点

        scanWithCurrentDetaB(line, mAreaMassif, detaB, points); // 初次调用
        return points;
    }


    /**
     * 根据 当前的b值，也就是每次变化喷幅个单位， y= kx + b ,去扫描地块，获得当前轮次的航点
     * @param route 最后的航点坐标 容器
     */
    private void scanWithCurrentDetaB(ScanLine line, AreaMassif areaMassif, double detaB, List<WaypointInfo> route) {


        //-----------
        areaMassif.scanLineInterPoints.clear();
        List<WaypointInfo> list0 = areaMassif.getThInterPointOfScanLineAndBoundrary(line);
        areaMassif.scanLineInterPoints.addAll(list0) ;
        int interPointSize = list0.size();
        //-----------


        boolean isFinish = areaMassif.isScanFinished(interPointSize ,route); //！！

        if (!isFinish) {
            line.addDaltaB(detaB); // 移动一个喷幅
            scanWithCurrentDetaB(line, areaMassif, detaB, route); //递归调用
        }
    }

}
